<html>
    <head>
        <title>概览 </title>
    </head>
    <body>
        <script>
            // 概览
                /*
                    授权用于检查是否允许用户在应用程序中执行某些操作。

                    ABP通过添加"权限"作为"自动策略"来扩展 asp.net core 核心授权，并允许授权系统可在应用服务中使用。

                    因此，所有所有ASP.NET核心授权功能和留档在基于ABP的应用程序中都是有效的。
                */


                // 一、Authorize 特性 (授权特性)

                        /*
                            Asp.net core 定义了  Authorize 属性，该属性可用于控制器方法（Action）、控制器(Controller)或者 页面。
                            ABP同时也允许你对"应用程序服务"使用Authorize
                        */
                        /*
                                    using System;
                                    using System.Collections.Generic;
                                    using System.Threading.Tasks;
                                    using Microsoft.AspNetCore.Authorization;
                                    using Volo.Abp.Application.Services;

                                    namespace Acme.BookStore
                                    {
                                        [Authorize] //控制器级别授权
                                        public class AuthorAppService : ApplicationService, IAuthorAppService
                                        {
                                            public Task<List<AuthorDto>> GetListAsync()
                                            {
                                                ...
                                            }

                                            [AllowAnonymous]  // action级别授权 允许匿名用户访问该方法
                                            public Task<AuthorDto> GetAsync(Guid id)
                                            {
                                                ...
                                            }

                                            [Authorize("BookStore_Author_Create")] // action级别授权 允许拥有"BookStore_Author_Create"权限的用户访问该方法
                                            public Task CreateAsync(CreateAuthorDto input)
                                            {
                                                ...
                                            }
                                        }
                                    }


                                Aothorize 特性强制用户登录应用程序以后才可使用 AuthorAppService方法。 因此，GetListAsync方法仅对经过身份验证的用户可用。

                                AllowAnonymous 特性，抑制身份验证。因此，GetAsync方法可供所有人使用，包括未经授权的用户

                                [Authorize("BookStore_Author_Create")]定义了一个策略（请参阅基于策略的授权），该策略被检查以授权当前用户
                        */


                // 二、Permission System 权限系统
                        /*
                                "权限"是为特定用户、角色 或者 客户端 授予或禁止的 "简单策略"。
                        */

                        /*
                            1、定义权限  Definiing Permissions
                                    
                                    要定义权限，请创建一个继承自 "PermissionDefinitionProvider"的类：
                                                
                                    using Volo.Abp.Authorization.Permissions; // 引用权限命名空间

                                    namespace Acme.BookStore.Permissions
                                    {
                                           public class BookStorePermissionDefinitionProvider: PermissionDefinitionProvider
                                           {
                                                // 重写 Define 方法，在里面定义权限组和权限。
                                                public override void Define(PermissionDeifnitionContext context)
                                                {
                                                    var myGroup = context.addGroup("BookStore");
                                                    myGroup.addPermission("BookStore.Author");
                                                }
                                           } 
                                    }

                                    ABP 会自动发现此类。无需额外配置！  

                                    在 Define 方法中，首先需要添加"权限组" 或者获取现有权限组，然后将"权限"添加到权限组中去。

                                    定义权限时，它在asp.net core 授权系统中可用作“策略名称”。他在UI中也变得可见。

                                    在数据库中会有一个名为 AbpPermissionGroups (权限组表)：用于存储权限组信息
                                               有一个名为 AbpPermissionGrants (权限授予表)：用于存储用户、角色和客户端的权限信息
                                    
                                    所以，权限的授予和权限组是分开存储，持久化到数据库的。
                        */

                        /*
                            2、检查权限
                                    ①、声明式检查权限：
                                                使用 [Authorize] 特性来检查权限。
                                                    
                                                    public class AuthorAppService : ApplicationService, IAuthorAppService
                                                    {
                                                        public Task<List<AuthorDto>> GetListAsync()
                                                        {
                                                            ...
                                                        }

                                                        [AllowAnonymous]  // action级别授权 允许匿名用户访问该方法
                                                        public Task<AuthorDto> GetAsync(Guid id)
                                                        {
                                                            ...
                                                        }

                                                        [Authorize("BookStore_Author_Create")] // 使用声明式检查权限（Action级别权限检查）
                                                        public Task CreateAsync(CreateAuthorDto input)
                                                        {
                                                            ...
                                                        }
                                                    }

                                    ②、编程式检查权限：
                                                使用 IAuthorizationService 接口来检查权限。

                                                public class AuthorAppService : ApplicationService, IAuthorAppService
                                                {
                                                    private readonly IAuthorizationService _authorizationService;

                                                    public AuthorAppService(IAuthorizationService authorizationService)
                                                    {
                                                        _authorizationService = authorizationService;
                                                    }

                                                    public async CreateAsync(CreateAuthorDto input)
                                                    {
                                                        // 编程式检查权限（Action级别权限检查）
                                                        var result = await _authorizationService.AuthorizeAsync(User, "BookStore_Author_Create");
                                                        if (!result.Succeeded)
                                                        {
                                                            throw new AbpAuthorizationException("You are not authorized to create an author!");
                                                        }

                                                        // 编程式检查权限（Action级别权限检查）
                                                        if(await _authorizationService.IsGrantedAsync("BookStore_Author_Create")
                                                        {
                                                        
                                                        }
                                                    }
                                                }

                                                IsGrantedAsync 方法用于检查当前用户（或用户的角色）是否被授予了给定的权限。
                                                如果没有权限执行当前操作时，会抛出 AbpAuthorizationException 异常。
                        */

                        /*
                            3、在客户端访问权限信息
                                    ABP框架公开了一个标准的HTTP API，
                                    URL为 /api/abp/application-configuration, 此api返回一个json对象，包含 "本地化文本"、"设置"、"权限"。

                                    客户端应用程序可以使用该api来验证权限，或者在客户端实现本地化。

                                    不同的客户端可能需要不同的权限验证服务。eg,在 mvc / Razor Pages 应用程序中，可以使用 JavaScript Api（abp.auth）来验证权限。

                                                    js代码： abp.auth.isGranted('ProductManagement.ProductCreation')

                                                    abp.auth.isGranted()  是一个全局函数。
                        */

                        /*
                            4、子权限
                                    在复杂的应用程序中，可能需要创建一些依赖于"父权限"的"子权限"。

                                    子权限只有在已经获得父权限时才有意义。


                                        public override void Define(IPermissionDefinitionContext context)
                                        {
                                            var myGroup =context.AddGroup("ProductManagement",L("ProductManagement")) // 返回刚刚创建的 权限组对象
                                                                                            // 第二个参数是本地化文本，可选的。如果不提供，则使用权限名称作为默认值

                                            var parent =myGroup.AddPermission("MyParentPermission"); // 返回刚刚创建的权限对象

                                            pareent.AddChild("MyChildPermission"); // 添加子权限
                                        }


                                     eg：
                                         var authorManagement = myGroup.AddPermission("Author_Management");
                                         authorManagement.AddChild("Author_Management_Create_Books");
                                         authorManagement.AddChild("Author_Management_Edit_Books");
                                         authorManagement.AddChild("Author_Management_Delete_Books");

                                     对于上面示例代码，假设授予“Author_Management”权限的角色/用户可能具有额外的权限。然后可以定义一个检查权限的典型应用程序服务，如下所示：

                                            [Authorize("Author_Management")]  // 检查父权限
                                            public class AuthorAppService : ApplicationService, IAuthorAppService
                                            {
                                                public Task<List<AuthorDto>> GetListAsync()
                                                {
                                                    ...
                                                }

                                                public Task<AuthorDto> GetAsync(Guid id)
                                                {
                                                    ...
                                                }

                                                [Authorize("Author_Management_Create_Books")]  // 检查子权限
                                                public Task CreateAsync(CreateAuthorDto input)
                                                {
                                                    ...
                                                }

                                                [Authorize("Author_Management_Edit_Books")]  // 检查子权限
                                                public Task UpdateAsync(CreateAuthorDto input)
                                                {
                                                    ...
                                                }

                                                [Authorize("Author_Management_Delete_Books")]  // 检查子权限
                                                public Task DeleteAsync(CreateAuthorDto input)
                                                {
                                                    ...
                                                }
                                            }   
                                                
                                    GetListAsync和GetAsync将可供用户使用，如果他们有Author_Management权限被授予。
                                    其他方法需要额外的权限。
                        */

                        /*
                            5、本地化权限名称
                                    "BookStore_Author_Create" 对于前端UI来说不是和好的权限名称。
                                    幸运的是， Addpermission 和 AddGroup 方法可以将 "本地化文本（LocalizableString）"作为第二个参数：

                                        var myGroup = context.AddGroup("ProductManagement", L("ProductManagement")); // 第二个参数为权限组的本地化文本
                                        var parent = myGroup.AddPermission("MyParentPermission", L("MyParentPermission")); // 第二个参数为权限组的本地化文本
                                        pareent.AddChild("MyChildPermission", L("MyChildPermission")); // 第二个参数为权限组的本地化文本

                                        然后你可以在本地化文件中为“BookStore”和“权限：BookStore_Author_Create”键定义文本：
                                            "BookStore": "Book Store",
                                            "Permission:BookStore_Author_Create": "Creating a new author"                 
                        */

                        /*
                            6、多租户权限处理
                                  ABP支持多租户作为一等公民。你可以在定义新权限的同时定义"多租户端选项"。
                                
                                  多租户端选项值有以下三个：
                                            ①、Host： 该权限适用于主机端
                                            ②、Tenant: 该权限适用于租户端
                                            ③、Both： 该权限适用于主机端和租户端

                                  默认情况下，权限是针对租户的。
                                  
                                        var myGroup = context.AddGroup("ProductManagement", L("ProductManagement")); // 默认针对租户端
                                        
                                        // 第三个参数是多租户端选项，默认为 MultiTenancySides.Tenant
                                        var myGroup = context.AddGroup("ProductManagement", L("ProductManagement"), multiTenancySide: MultiTenancySides.Host); // 针对主机端
                        */

                        /*
                            7、启用/禁用权限

                                    默认情况下启用权限。可以禁用权限。禁止所有人使用禁用的权限。你仍然可以检查权限，但它将始终返回禁止。

                                    示例定义：
                                        myGroup.AddPermission("Author_Mnagement",isEnabled:false);  // 声明禁用的权限

                                    你通常不需要定义禁用的权限，除非你想暂时禁用应用程序的某些功能。
                                    但是，你可能希望禁用依赖模块中的权限（通过这种方式，你可以禁用相关的应用程序功能）。
                                    有关示例方法，请参阅下面的 "更改依赖模块中的权限定义"部分。
                        */

                        /*
                            8、通过自定义策略覆盖权限
                                    如果你使用相同的权限名称定义并向ASP.NETCore授权系统注册策略，你的策略将覆盖现有权限。
                                    这是扩展你在应用程序中使用的预构建模块的授权的强大方法。

                                    请参阅"基于策略的授权文档"以了解如何定义自定义策略。
                        */

                        /*
                            9、更改依赖模块的权限定义
                                    从 PermissionDefinitionProvider 派生的类也可以获取现有的权限定义（由现有的依赖模块的权限定义）：

                                                context.GetPermissionOrNull(IdentityPermission.Roles.Delete)
                                                        .IsEnabled =false;  // 禁用现有权限
                                    当你在权限定义提供程序中编写此代码时，它会找到Identity 模块的"角色删除"权限并禁用该权限，因此没有人可以删除应用程序上的角色。
                                    
                                    注意： 最好检查GetPermissionOrNull 返回的值是否为null，以防万一该权限不存在。
                        */

                        /*
                            10、条件性启用权限
                                   你可能希望"根据条件禁用权限"。禁用的条件在UI上不可见，并且在你检查它们的时候始终返回"禁止(prohibited)".

                                   权限的定义有两个内置条件依赖项：

                                        ①、如果禁用了权限依赖的功能(Feature)，则可以自动禁用权限：

                                                    myGroup.AddPermission("Book_Creation")
                                                           .RequireFeatures("BookManagement"); // 扩展方法，定义功能依赖

                                        ②、如果禁用了依赖的全局功能(GlobalFeature),则可以自动禁用权限。
                                                    myGroup.AddPermission("Book_Creation")
                                                           .RequireGlobalFeatures("BookManagement"); // 扩展方法，定义全局功能依赖
                        */

                        /*
                            11、创建自定义权限依赖项：
                                    PermissionDefinition支持状态检查，请参考 "Simple State Checker"部分的文档。    
                        */


            //  三、 IAuhorizationService 授权服务接口 (此接口是来自.net core 的授权服务)

                        /*
                                asp.net core 提供了可用于检查权限的 IAuthorizationService 服务。
                                一旦注入此服务，就可以在代码中使用它来 "有条件的控制授权"

                                eg：
                                    public async Task CreateAsync(CreateAuthorDto input)
                                    {
                                        var result = await AuthorizationService.AuthorizeAsync("Author_Management_Create_Books")；

                                        if(result.Succeeded==false)
                                        {
                                             //抛出授权异常
                                             throw new AbpAuthorizationException("...");
                                        }
                                    }

                                AuthorizationService在你的ABP 应用服务类(继承自ApplicationService)有一个同名的属性(来自ApplicationService基类)。
                                因为在应用层的服务中经常要用，所有ABP就把他放在了ApplicationService基类中。

                                所以，上面的代码可以简化为：
                                    public async Task CreateAsync(CreateAuthorDto input)
                                    {
                                        // CheckAsync 为扩展方法，会抛出AbpAuthorizationException。
                                        // 还有IsGrantedAsync扩展方法,返回true或false
                                        await AuthorizationService.CheckAsync("Author_Management_Create_Books")； // 抛出异常，无需捕获(自动抛出AbpAuthorizationException异常)



                                        // 正常的执行流......
                                    }

                                // IAuthorizationService对AuthorizeAsync方法有一些重载。这些在ASP.NET Core 文档中有描述。
                        */

                // 四、权限管理
                        /*
                            1、通过"权限管理界面"进行权限管理

                            2、通过代码管理权限 （IPermisssionManager接口）
                                
                                    如果需要通过代码管理权限，注入IPermissionManager并使用如下所示：

                                        public class MyService : ITransientDependency
                                        {
                                            private readonly IPermissionManager _permissionManager;

                                            public MyService(IPermissionManager permissionManager)
                                            {
                                                _permissionManager = permissionManager; // 注入IPermissionManager接口
                                            }

                                            // 授予权限
                                            public async Task GrantPermissionForUserAsync(Guid userId, string permissionName)
                                            {
                                                await _permissionManager.SetForUserAsync(userId, permissionName, true);
                                            }

                                            // 接除权限授予
                                            public async Task ProhibitPermissionForUserAsync(Guid userId, string permissionName)
                                            {
                                                await _permissionManager.SetForUserAsync(userId, permissionName, false);
                                            }
                                        }        

                                    SetForUserAsync设置用户权限的值（真/假）。还有更多的扩展方法，如SetForRoleAsync和SetForClientAsync。

                                    注意： IPermissionManager由权限管理模块定义
                        */
        </script>
    </body>
</html>